package cc.rengu.igas.channel.cups.core.packswitch;

import cc.rengu.igas.channel.cups.common.constant.CupsConfigConstant;
import cc.rengu.igas.channel.cups.common.constant.CupsParamConstant;
import cc.rengu.igas.channel.cups.common.constant.CupsTreeNodeConstant;
import cc.rengu.igas.channel.cups.common.enums.RespCodeEnum;
import cc.rengu.igas.channel.cups.core.realize.CupsMacService;
import cc.rengu.igas.channel.cups.core.realize.impl.CupsMacServiceImpl;
import cc.rengu.jradp.packetswitch.IncomingPackSwitchImpl;
import cc.rengu.jradp.packetswitch.OutgoingPackSwitchImpl;
import cc.rengu.jradp.schedule.Schedule;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.KeyInfoMapper;
import cc.rengu.oltp.service.common.dao.SecPlanInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.KeyInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.SecPlanInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.DstChannelInfo;
import cc.rengu.oltp.service.common.entity.KeyInfo;
import cc.rengu.oltp.service.common.entity.SecPlanInfo;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.utility.util.ByteUtil;
import cc.rengu.oltp.utility.util.XmlConfigUtil;
import cc.rengu.oltp.utility.util.XmlTreeUtil;
import cc.rengu.utility.cache.UnifiedCache;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import com.alibaba.fastjson.JSON;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;

/**
 * 与银联cups通讯
 *
 * @author Administrator
 */
@SuppressWarnings("AlibabaLowerCamelCaseVariableNaming")
public class CupsClientPackSwitch implements IncomingPackSwitchImpl, OutgoingPackSwitchImpl {

    @Override
    public byte[] afterOutgoPackSwitch(byte[] arg0) throws Exception {
        XmlTreeUtil tree = new XmlTreeUtil();
        /*请求报文转换后对整个报文TotalMsgLen重新填写值*/
        int totalMsgLength = arg0.length;
        String strTotalLen = String.format("%04d", totalMsgLength);
        byte[] tmp = strTotalLen.getBytes(StandardCharsets.UTF_8);
        System.arraycopy(tmp, 0, arg0, 2, 4);
        /*前46字节为CUPS/HEADER_BUF*/
        byte[] headerByte = new byte[46];
        System.arraycopy(arg0, 0, headerByte, 0, 46);
        String headerBuf = ByteUtil.bytesToHexString(headerByte);
        tree.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_HEADER_BUF, headerBuf);
        /*报文转换之后去除请求和应答都使用的域；防止不应答该域时请求域对其干扰，目前请求应答皆使用且内容不一致的为55域*/
        tree.deleteXmlTreeNode(CupsTreeNodeConstant.CUPS_IC_DATA);
        return arg0;
    }

    @Override
    public int beforeOutgoPackSwitch() throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        XmlTreeUtil tree = new XmlTreeUtil();
        Schedule schedule = new Schedule();
        SetCupsHeader();
        StringBuilder buf = new StringBuilder();
        /*对于发送CUPS请求，则设置缓存（交易码+系统流水号），匹配应答*/
        String txnNum = tree.getXmlTreeStringValue(TreeNodeConstant.TXN_NUM);
        if (null == txnNum) {
            rglog.error("获取通道交易码失败，节点为{}", CupsTreeNodeConstant.CUPS_TXN_NUM);
            return -1;
        }
        String transDateTime = tree.getXmlTreeStringValue(CupsTreeNodeConstant.CUPS_TXN_DATE_TIME);
        buf.append(transDateTime);
        String cupsSsn = tree.getXmlTreeStringValue(CupsTreeNodeConstant.CUPS_CUP_SN);
        buf.append(cupsSsn);
        String acqInstCode = tree.getXmlTreeStringValue(CupsTreeNodeConstant.CUPS_ACQ_INST_ID_CODE);
        if (acqInstCode != null) {
            buf.append(acqInstCode);
        }
        String fwdInstCode = tree.getXmlTreeStringValue(CupsTreeNodeConstant.CUPS_FWD_INST_ID_CODE);
        if (fwdInstCode != null) {
            buf.append(fwdInstCode);
        }
        String tunlSsn = buf.toString();
        tree.setXmlTreeStringValue(TreeNodeConstant.CHANNEL_SEQ_NUM, tunlSsn);
        String platformId = schedule.getPlatformId();
        if (null == platformId) {
            rglog.error("获取平台ID失败");
            return -1;
        }
        rglog.debug("获取平台ID为{}", platformId);
        //缓存通道流水号，长链应答匹配
        if (UnifiedCache.get(CupsParamConstant.CACHE_CUPS_SN, tunlSsn) != null) {
            //对于多次发起的冲正交易，其3，7，11没有变化，因此控制冲正交易正在冲正时（及该缓存还没有删除时）不允许冲正
            rglog.error("交易{}流水号{}已经存在", txnNum, tunlSsn);
            return -1;
        } else {
            int ret = UnifiedCache.set(CupsParamConstant.CACHE_CUPS_SN, tunlSsn, platformId);
            rglog.error("缓存=[{}],key=[{}],value=[{}]", CupsParamConstant.CACHE_CUPS_SN, tunlSsn, platformId);
            if (ret != 0) {
                rglog.error("设置交易{}流水号{}缓存失败", txnNum, tunlSsn);
                return -1;
            }
        }
        String macBlock = tree.getXmlTreeStringValue(CupsTreeNodeConstant.CUPS_MAC_BLOCK);
        if (macBlock != null) {
            KeyInfo keyInfo = null;
            DstChannelInfo dstChannelInfo = (DstChannelInfo) tree.getXmlTreeObjectValue(CupsTreeNodeConstant.DST_CHANNEL_INFO, DstChannelInfo.class);
            tree.setXmlTreeStringValue(TreeNodeConstant.INST_ID, dstChannelInfo.getInstId());
            /* 根据通道安全计划获取安全计划 */
            SecPlanInfoMapper secPlanInfoMapper = new SecPlanInfoMapperImpl();
            List<SecPlanInfo> secPlanInfoList = secPlanInfoMapper.selectSecPlanInfoBySecPlanId(dstChannelInfo.getInstId(), dstChannelInfo.getSecPlanId());
            if (null != secPlanInfoList && !secPlanInfoList.isEmpty()) {
                tree.setXmlTreeStringValue(CupsTreeNodeConstant.SEC_PLAN_INFO_LIST, JSON.toJSONString(secPlanInfoList));
                /* mac密钥 */
                Optional<SecPlanInfo> secPlanInfoOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(CupsParamConstant.MAC_KEY_TYPE)).findFirst();
                if (secPlanInfoOpt.isPresent()) {
                    KeyInfoMapper keyInfoMapper = new KeyInfoMapperImpl();
                    keyInfo = keyInfoMapper.selectKeyInfoByPrimaryKey(dstChannelInfo.getInstId() + secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
                }
            }
            if (keyInfo == null) {
                throw new BizException(RespCodeEnum.GET_KEY_INFO_ERROR.getRespCode(), RespCodeEnum.GET_KEY_INFO_ERROR.getRespDesc());
            }
            tree.setXmlTreeObjectValue(CupsTreeNodeConstant.CUPS_MAC_KEY_INFO, keyInfo);

            CupsMacService cupsMacService = new CupsMacServiceImpl();
            String mac = cupsMacService.genMacString(keyInfo, macBlock);
            if (mac == null) {
                rglog.error("生成mac失败");
                return -1;
            }
            tree.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_MAC_VAL, ByteUtil.bytesToHexString(mac.substring(0, 8).getBytes(CupsParamConstant.GB18030)));
        }

        return 0;
    }

    @Override
    public int afterInComPackSwitch() {

        return 0;
    }

    /**
     * 报文转换之前确定CUPS应答报文为正确报文或者是错误报文
     * 根据报文头中的拒绝码确定：
     * 若拒绝码不为00000，则该报文为错误报文，存在一个新增报文头与原始的请求报文；
     * 并且可以根据拒绝码确定请求报文的具体错误
     * 否则为正确报文，可以使用配置解析
     */
    @Override
    public byte[] beforeInComPackSwitch(byte[] arg0) throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        XmlTreeUtil tree = new XmlTreeUtil();
        //前46字节为CUPS/HEADER_BUF
        byte[] headerByte = new byte[46];
        System.arraycopy(arg0, 0, headerByte, 0, 46);
        String headerBuf = ByteUtil.bytesToHexString(headerByte);
        tree.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_RSP_HEADER_BUF, headerBuf);

        byte[] rejectCode = new byte[5];
        System.arraycopy(arg0, 41, rejectCode, 0, 5);
        String strRejectCode = new String(rejectCode, StandardCharsets.UTF_8);

        if ("00000".equals(strRejectCode)) {
            return arg0;
        } else {
            rglog.error("cups return reject code=[{}]", strRejectCode);
            return null;
        }
    }

    private void SetCupsHeader() throws Exception {
        XmlTreeUtil tree = new XmlTreeUtil();
        /* 加载公共信息 */
        //头长度Header Length（0x2E)headerLen
        String headerLen = "2E";
        tree.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_HEADER_LEN, headerLen);
        /*头标识和版本号Header Flag and Version(生产0x02，测试0x82)flagVersion*/
        String flagVersion = XmlConfigUtil.getXmlConfigCacheKeyValue(CupsConfigConstant.CUPS_CONF_NODE, CupsConfigConstant.CUPS_VERSION);
        if (flagVersion == null) {
            flagVersion = "02";
        }
        tree.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_FLAG_VERSION, flagVersion);

        /*totalMsgLen整个报文长度Total Message Length(报文发送前由after填入，大于46，小于1846)*/
        String totalMsgLen = "0000";
        tree.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_TOTAL_MSG_LEN, totalMsgLen);

        /*目的ID（00010000）destId*/
        String destId = XmlConfigUtil.getXmlConfigCacheKeyValue(CupsConfigConstant.CUPS_CONF_NODE, CupsConfigConstant.CUPS_ID);
        if (destId == null) {
            destId = "00010000";
        }
        tree.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_DEST_ID, destId);

        /*源ID（总行机构代码）srcId*/
        String srcId = XmlConfigUtil.getXmlConfigCacheKeyValue(CupsConfigConstant.CUPS_CONF_NODE, CupsConfigConstant.CUPS_FWD_INS_CODE);
        tree.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_SRC_ID, srcId);

        /*保留使用（0x000000）reservedUse*/
        String reservedUse = XmlConfigUtil.getXmlConfigCacheKeyValue(CupsConfigConstant.CUPS_CONF_NODE, CupsConfigConstant.CUPS_RESERVED);
        if (reservedUse == null) {
            reservedUse = "000000";
        }
        tree.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_RESERVED_USE, reservedUse);

        /*批次号(0x00)batchNumber*/
        String batchNumber = XmlConfigUtil.getXmlConfigCacheKeyValue(CupsConfigConstant.CUPS_CONF_NODE, CupsConfigConstant.CUPS_BATCH_NO);
        if (batchNumber == null) {
            batchNumber = "00";
        }
        tree.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_BAT_NUM, batchNumber);

        /*交易信息(00000000)transInfo*/
        String transInfo = XmlConfigUtil.getXmlConfigCacheKeyValue(CupsConfigConstant.CUPS_CONF_NODE, CupsConfigConstant.CUPS_TRANS_INFO);
        if (transInfo == null) {
            transInfo = "00000000";
        }
        tree.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_TRANS_INFO, transInfo);

        /*用户信息(0x00)userInfo*/
        String userInfo = XmlConfigUtil.getXmlConfigCacheKeyValue(CupsConfigConstant.CUPS_CONF_NODE, CupsConfigConstant.CUPS_USER_INFO);
        if (userInfo == null) {
            userInfo = "00";
        }
        tree.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_USER_INFO, userInfo);

        /*拒绝码(00000)rejectCode*/
        String rejectCode = XmlConfigUtil.getXmlConfigCacheKeyValue(CupsConfigConstant.CUPS_CONF_NODE, CupsConfigConstant.CUPS_REJECT_CODE);
        if (rejectCode == null) {
            rejectCode = "00000";
        }
        tree.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_REJECT_CODE, rejectCode);

        StringBuilder buf = new StringBuilder(92);
        buf.append(headerLen);
        buf.append(flagVersion);
        byte[] msgLenByte = totalMsgLen.getBytes(StandardCharsets.UTF_8);
        byte[] destIdByte = String.format("%-11.11s", destId).getBytes(StandardCharsets.UTF_8);
        byte[] srcIdByte = String.format("%-11.11s", srcId).getBytes(StandardCharsets.UTF_8);
        byte[] transInfoByte = transInfo.getBytes(StandardCharsets.UTF_8);
        byte[] rejectCodeByte = rejectCode.getBytes(StandardCharsets.UTF_8);

        buf.append(ByteUtil.bytesToHexString(msgLenByte));
        buf.append(ByteUtil.bytesToHexString(destIdByte));
        buf.append(ByteUtil.bytesToHexString(srcIdByte));
        buf.append(reservedUse);
        buf.append(batchNumber);
        buf.append(ByteUtil.bytesToHexString(transInfoByte));
        buf.append(userInfo);
        buf.append(ByteUtil.bytesToHexString(rejectCodeByte));
        tree.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_HEADER_BUF, buf.toString());
    }
}
